Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REVIEW] install cmake config file with RMM #580

Merged
merged 19 commits into from
Oct 2, 2020

Conversation

germasch
Copy link
Contributor

supersedes #462 -- a lot of cmake stuff has changed since, so it makes sense to do this over.

This PR first switches to using GNUInstallDirs to determine paths where to write includes / libraries. This doesn't change existing behavior, but it does make it easier for, e.g., distros to set custom install paths.

The main thing, though, is that it adds rmm-config.cmake and friends that allow for easier consumption of RMM in downstream projects, ie.,

find_package(rmm 0.16 REQUIRED)
# ...
target_link_libraries(my_app rmm::rmm)

This PR does not yet handle the thirdparty dependency on thrust -- I'll add that after #579 is resolved. It does, however, handle the dependency on spdlog, which serves as an example on how thirdparty are handled:

Since RMM is now using CPM, there are two cases, depending on whether spdlog is present. In either case, the rmm::rmm target will records its dependency on spdlog (as well as cudart and thrust), which has to be resolved when pulling in the package via find_package as above.

  1. spdlog is found as a locally installed package (e.g., installed through conda). In this case, the spdlog dependency is resolved through a find_dependency(spdlog 1.17.0) which happens automatically inside of the find_package() call above. This assumes that spdlog is installed on the system where the installed RMM is used (and will error if no spdlog can be found).

  2. spdlog was not locally installed, so RMM pulled in spdlog via FetchContent. In this case, since a downstream user needs to have spdlog in order to (fully) use RMM, spdlog is installed together with RMM on make install. The downstream app will end up using RMM and its bundled spdlog.

This does change existing behavior in the 2nd case in that spdlog is built and installed together with RMM. It should not break anything, but takes some additional build time. Hitting the 2nd case should be rare, though -- when using, e.g., conda, spdlog will be available and one will hit case 1, where existing behavior does not change (except for installing a few additional cmake config files).

This doesn't change behavior by default, but it does allow, e.g., distro
package managers to impose their own directory structure. (And it's not
really GNU specific)
@germasch germasch requested a review from a team as a code owner September 27, 2020 02:34
@GPUtester
Copy link
Contributor

Can one of the admins verify this patch?

1 similar comment
@GPUtester
Copy link
Contributor

Can one of the admins verify this patch?

If RMM is used in a downstream project via `find_package(rmm)`, it'll
provide the namespaced rmm::rmm target. If it's used via
`add_subdirectory()` it creates its usual `rmm` target, but with this
change it creates an `rmm::rmm` alias, too.
@germasch
Copy link
Contributor Author

Could someone say "ok to test"? ;)

@kkraus14
Copy link
Contributor

Ok to test

@jrhemstad
Copy link
Contributor

Can we look into using PackageProject here?

@germasch
Copy link
Contributor Author

Can we look into using PackageProject here?

I looked at it. It doesn't quite work, once Thrust is added, since it assumes it can just do a bunch of find_dependency(...) calls, but we need to have a thrust_create_target(), too. I don't think it has a way to add cmake_minimum_required() into the config file, either, which is advisable since we're relying on find_package(CUDAToolkit), which is relatively recent.

We could possibly submit PRs to PackageProject to make it more customizable so that it could fit the needs, but in the end I'm not sure we end up with something simpler.

CMakeLists.txt Outdated Show resolved Hide resolved
@germasch germasch changed the title [WIP] install cmake config file with RMM [REVIEW] install cmake config file with RMM Sep 29, 2020
@kkraus14 kkraus14 added 3 - Ready for review Ready for review by team and removed 2 - In Progress Currently a work in progress labels Sep 29, 2020
CMakeLists.txt Outdated Show resolved Hide resolved
CMakeLists.txt Outdated Show resolved Hide resolved
Copy link
Member

@harrism harrism left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. Just suggesting some streamlining of the (already very nice) docs you added, such as converting future tense to present tense for clarity.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
Co-authored-by: Keith Kraus <[email protected]>
Co-authored-by: Mark Harris <[email protected]>
@germasch
Copy link
Contributor Author

germasch commented Sep 29, 2020

Oops, I just found this comment I wrote in github a couple of days ago, but apparently never actually submitted.
This PR should not be merged before settling this.

So it's time to talk about the caveats.

First of all, the potential for breaking something that currently works is fairly low. Essentially, this PR only adds some new cmake config files that are installed alongside rmm's headers.

But there are some complications related to thrust:

Currently, the installed target does depend on spdlog::spdlog_header_only, CUDA::cudart and rmm::Thrust. The first two are pulled in automatically when doing find_package(rmm), but not yet rmm::Thrust.

So that's why it's WIP, it's only actually usable by a downstream project if the downstream project hacks around this limitation.

I think there are two options to handle this:

  1. drop the explicit dependency on rmm::Thrust for now.
  2. pull in Thrust 1.10.0 via find_dependency.

Option 1 would make things work without trouble for the typical downstream project. They'd likely end up using the thrust installed with their CUDA toolkit, which is probably good enough for them. If they do care about a newer thrust, they'd pull that in explicitly, and it'd get used.

Option 2 is the more correct way of doing things, but it also makes it harder to actually use rmm via find_package(rmm). There are a number of reasons:

I'm kinda ambivalent about what the best way to proceed is. One could choose option 1 for now and switch to doing things properly once a new version of thrust is released (or once the PRs above are merged, depend on a specific version from thrust's main branch). Or do option 2 correctly already, which means that things will only really become usable as thrust gets updated.

FWIW, this is the diff for option 2:

diff --git a/cmake/RMM_thirdparty.cmake b/cmake/RMM_thirdparty.cmake
index 319d031..ab5abbc 100644
--- a/cmake/RMM_thirdparty.cmake
+++ b/cmake/RMM_thirdparty.cmake
@@ -23,6 +23,10 @@ CPMFindPackage(
   GIT_TAG 1.10.0
   VERSION 1.10.0
   GIT_SHALLOW TRUE
+  OPTIONS
+    # If there is no pre-installed thrust we can use, we'll install our fetched copy
+    # together with RMM
+    "THRUST_INSTALL TRUE"
   )

 thrust_create_target(rmm::Thrust FROM_OPTIONS)
diff --git a/rmm-config.cmake.in b/rmm-config.cmake.in
index a720acf..617828f 100644
--- a/rmm-config.cmake.in
+++ b/rmm-config.cmake.in
@@ -6,6 +6,8 @@ cmake_minimum_required(VERSION 3.17)
 include(CMakeFindDependencyMacro)
 find_dependency(CUDAToolkit)
 find_dependency(spdlog 1.7.0)
+find_dependency(Thrust 1.10.0)
+thrust_create_target(rmm::Thrust FROM_OPTIONS)

 include("${CMAKE_CURRENT_LIST_DIR}/rmm-targets.cmake")
 include("${CMAKE_CURRENT_LIST_DIR}/rmm-config-version.cmake")

Option 1 would be simply going to back to using $<BUILD_INTERFACE:...> for the dependency on rmm::Thrust, so that it doesn't get recorded in the installed package.

@germasch
Copy link
Contributor Author

@harrism, I committed all of your suggested doc changes, btw -- thanks!

@harrism
Copy link
Member

harrism commented Oct 1, 2020

Just FYI, I think RMM should work fine with thrust 1.9.x. HOWEVER, libcudf needs Thrust 1.10+ I think and the most common use cases of RMM also use cuDF.

@germasch
Copy link
Contributor Author

germasch commented Oct 1, 2020

So given the timeframe for the next release, I'm inclined to address the last little hitch that I'm aware of in this PR as well (besides finishing the thrust issue):

Right now, RMM does this:

if(USE_NVTX)
  message(STATUS "Using Nvidia Tools Extension")
else()
  target_compile_definitions(rmm INTERFACE NVTX_DISABLE)
endif(USE_NVTX)

By default, USE_NVTX is off, which adds -DNVTX_DISABLE to the flags, and as such, the installed cmake configuration picks that up and hence a downstream project using RMM may unexpectedly end up with its NVTX disabled.

So this flag is something that maybe should be set for the benchmarks, but not generally for RMM and all of its consumers. Right now, it really doesn't need to be set at all, since I believe no nvtx is used anywhere at all.

An easy solution would be to get rid of the above, since it isn't even being used. That would also allow to reintroduce it later as RMM_USE_NVTX, if desired. But I'm not sure it's really clear at this point in which fashion nvtx would best be handled, anyway.

@harrism
Copy link
Member

harrism commented Oct 1, 2020

You can remove the NVTX stuff. I have an open PR that I plan to update in the next release to add some NVTX regions and I can add a new flag there if necessary.

@harrism
Copy link
Member

harrism commented Oct 1, 2020

Note that while burndown means "no new PRs", we still have about a week during burndown to finish in progress PRs.

Comment on lines 2 to 7
## Copyright (c) Kitware, Inc.
## All rights reserved.
## See LICENSE.txt for details.
## This software is distributed WITHOUT ANY WARRANTY; without even
## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
## PURPOSE. See the above copyright notice for more information.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the license for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's a good point. I guess it's this: https://gitlab.kitware.com/vtk/vtk-m/-/blob/783867eeb05e0a6538f9c520af02c3615651b4ed/LICENSE.txt. It does say

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

 * Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the
   distribution.

 * Neither the name of Kitware nor the names of any contributors may
   be used to endorse or promote products derived from this software
   without specific prior written permission.

So it seems pretty permissive, but IANAL.

I can write a custom one from scratch if this causes issues. Chances are it would look very similar, though, since really, the only thing that is not boilerplate in there is the version parsing, and that comes from Nvidia.

Copy link
Member

@harrism harrism Oct 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the BSD 3-clause license plus extra non-exclusive licenses from US govt labs and extra copyrights. That is one of the licenses we can easily use. We still have a process we need to follow to add a new piece of software. I will check if RAPIDS already has done this for CMake code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, we have approval, but before we can merge we need the complete license for this file included (ideally in this file).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so I copied in the full text from the LICENSE.txt above.

@germasch
Copy link
Contributor Author

germasch commented Oct 1, 2020

Note that while burndown means "no new PRs", we still have about a week during burndown to finish in progress PRs.

Yeah, I understand, that's why I didn't want to come with a little follow-up PR later. The latest push now removes USE_NVTX for the time being, and it also uses variables for the versions of thirdparty dependencies (thrust and spdlog).

There's some asymmetry in that we required Thrust >= 1.10.0 at build time (and fetch if necessary), but accept Thrust >= 1.9.0 when using the installed RMM. I think that's reasonable for the time being, though. I didn't leave a warning if Thrust < 1.10 ends up being used, but I can easily add one back if desired. When cmake finds an old Thrust version it will show what version it is, and its location, so it's at least somewhat visible in any case:

-- Found Thrust: /opt/spack/opt/spack/linux-ubuntu18.04-haswell/gcc-7.5.0/cuda-10.2.89-cdzvh6elxmxj3kela4cnnvrzpjy2ett4/include (found suitable version "1.9.7", minimum required is "1.9.0")

RMM will prefer a newer Thrust, found by config mode, though, before falling back to the old way.

There's a bit of a similar issue to USE_NVTX with PER_THREAD_DEFAULT_STREAM. But at least it's off by default, so it won't usually interfere. The nice thing about a header-only library is that one doesn't have to make these choices at build time for the library, hence it also would be better it they were not made (and recorded in the config). I think it'd better to just turn PTDS on (optionally) for the tests/benchmarks. (That also means one could have the tests compiled twice, with and w/o, where one wants to test both cases.)

Copy link
Contributor

@kkraus14 kkraus14 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved pending the license question

@harrism
Copy link
Member

harrism commented Oct 2, 2020

I just noticed that in an earlier commit you modified FindThrust.cmake, rather than just pulling it in without changes. That changes the process. I would have to start over with a much more involved legal process. Any chance of using the original unmodified FindThrust? (Or getting Thrust to provide their own?) Or somehow not needing FindThrust? (We didn't need it previously...)

This one now tries to find an install Thrust config first, and if
it's not found, it looks for Thrust itself, and also provides a
compatibility `thrust_create_target()` function.
@germasch
Copy link
Contributor Author

germasch commented Oct 2, 2020

I just noticed that in an earlier commit you modified FindThrust.cmake, rather than just pulling it in without changes. That changes the process. I would have to start over with a much more involved legal process. Any chance of using the original unmodified FindThrust? (Or getting Thrust to provide their own?)

I started over and implemented a FindThrust.cmake from scratch. This at least has the advantage that I could actually make it provide compatible behavior to the configs installed by thrust since 1.9.10, which simplifies the rmm-config.cmake quite a bit. The only three lines of code that aren't my own are from https://github.com/NVIDIA/thrust/blob/main/thrust/cmake/README.md, which mirror the version calculations done in thrust/version.h.

Or somehow not needing FindThrust? (We didn't need it previously...)

Well, a prior revision of this PR was like that, if a newer Thrust wasn't found by config, it'd just keep its fingers crossed that some other thrust would be found automatically at build time (which would usually work, since it's in the cuda toolkit). But I think what's there now is cleaner, and at some point in the future, when Thrust that comes with its own cmake config is commonly available, the FindThrust.cmake can just be removed and things will still work.

It's worth noting that this FindThrust.cmake is deliberately put into cmake/install/, where it won't be found or used during the RMM build at all. The only reason it's there is so that it's installed together with the rest of RMM, so that a downstream cmake project that uses RMM handles RMM's thrust dependency properly. This PR, for the most part adds a new feature (ie., some additional files get installed for downstream use) and keeps existing use almost untouched.

@harrism
Copy link
Member

harrism commented Oct 2, 2020

This is fantastic. Thanks very much for doing this. It's not that we couldn't use the VTK-m code, its just that I have to go through a different process with the lawyers if we plan to modify it.

BTW, if you ever want to discuss anything not directly related to a PR off of github, you can find us on the RAPIDS public slack linked from this page: https://rapids.ai/community.html

@harrism
Copy link
Member

harrism commented Oct 2, 2020

@kkraus14 you might want to have a look before we merge?

@kkraus14 kkraus14 added 5 - Ready to Merge Testing and reviews complete, ready to merge and removed 3 - Ready for review Ready for review by team labels Oct 2, 2020
@kkraus14 kkraus14 merged commit 7ee3510 into rapidsai:branch-0.16 Oct 2, 2020
@germasch germasch deleted the pr/cmake-install branch October 2, 2020 03:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
5 - Ready to Merge Testing and reviews complete, ready to merge CMake
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants